#!/usr/bin/env python
# razvan.coca@gmail.com

import config
import sys
import os,shutil
import pprint

WD=os.getenv('PWD')
os.chdir(WD)
sys.path.append(os.getcwd())

from ConfigFreemind import LoadConfig
from GenHelper import *

def printable(x):
    pDict={
        'boost::posix_time::milliseconds':'.ticks()',
        'boost::asio::ip::tcp::resolver::query':'.host_name()',
        'boost::asio::ip::tcp::endpoint':'.address()',
        'bptime::milliseconds':'.total_milliseconds()',
        'ba::ip::tcp::resolver::query':'.host_name()',
        'ba::ip::tcp::endpoint':'.address()',
        'ba::ip::icmp::endpoint':'.address()',
        'ba::ip::tcp::resolver::iterator':'->endpoint().address()',
        'ba::ip::udp::resolver::iterator':'->endpoint().address()',
        'ba::ip::udp::resolver::query':'.host_name()',
        'ba::ip::udp::endpoint':'.address()',
        'ba::ip::icmp::endpoint':'.address()',
        'ba::ip::udp::resolver::iterator':'->endpoint().address()',
        'bt::milliseconds':'.total_milliseconds()',
        'bt::millisec':'.total_milliseconds()',
        'std::vector<baio::ip::icmp::endpoint>':'.size()',
        'std::string':' ',
        'int':' ',
        'std::size_t':' ',
        'const bs::error_code':' ',
        'bool':' '
        }
    try:
        return pDict[x]
    except:
        return ""


def isAttr(x):
    return type(x)!=config.Mapping and type(x)!=config.Config 

def isClass(x):
    return type(x)==config.Mapping or type(x)==config.Config

def GetAttrs(ConfMap):
    descendants=ConfMap.keys()
    attrkeys=filter(lambda x:isAttr(ConfMap[x]),descendants)
    return dict([(k,ConfMap[k]) for k in attrkeys ])

def GetLayerClasses(ConfMap):
    descendants=ConfMap.keys()
    return filter(lambda x:isClass(ConfMap[x]),descendants)

def hasAttr(x):
    holds=[x[k[1]] for k in x.iteritems()]
    return filter(isAttr,holds)>0

def isEmptyClass(x):
    if isAttr(x):
        return False
    return all([isAttr(x[k]) or not 'name' in x[k].keys() for  k in x.keys()])

    
def argList(argenum):
    argstext=argenum.split(',')
    Args=[]
    for argt in argstext:
        pieces=map(lambda x:x.strip(),argt.split(' '))
        #print pieces
        pieces=filter(lambda x:len(x),pieces)
        if len(pieces)>1:
            Args.append([" ".join(pieces[:-1]),pieces[-1]])
    return Args


def argListFlat(arglist):
     return [" ".join(a) for a in arglist]

def argListFlatInline(arglist):
     return ", ".join([" ".join(a) for a in arglist]).strip()

def actualArgListFlat(arglist):
     return ", ".join([a[-1] for a in arglist]).strip()

def actualArgList(arglist):
     return [a[-1] for a in arglist]

def formalArgList(arglist):
     return [a[0] for a in arglist]

def signatureArgListFlat(arglist):
     return ", ".join([a[0] for a in arglist]).strip()

def signatureArgList(arglist):
     return [a[0].strip() for a in arglist]

def sameSignature(arglist,targlist):
    s1=signatureArgList(arglist)
    s2=signatureArgList(targlist)
    if len(s1)!=len(s2):return False
    return all(map(lambda x:x[0]==x[1],zip(s1,s2)))


def confLayerHasItems(Layer):
    return type(Layer)==config.Mapping or type(Layer)==config.Config

def isLeaf(layer):
    fv=filter(isClass,[x[1]  for x in layer.iteritems()])
    ffv=[y for x in fv for y in x.iteritems()]
    return all([not isClass(x[1]) for x in ffv])


def confIsSkippable(Conf):
    try:
        return Conf['skip'] in ['true','True',True,1]
    except:
        return False
    
def isSkippable(klass):
    if type(klass)==type([]):
        return any(map(isSkippable,klass))
    return getattr(klass,'skip',False) in ['true','True',True]

def get_op(Attrs):
    try:
        return Attrs['op']
    except:
        return ''
def get_ctor(Attrs):
    try:
        return Attrs['ctor']
    except:
        return ''
    
def get_handler_name(Attrs):
    try:
        return Attrs['handler_name']
    except:
        return handler_name(Attrs['name'])
def getservice(attrs):
    try:
        return attrs['service']
    except:
        return ""  
def getstrand(attrs):
    try:
        return attrs['strand']
    except:
        return ""

def getinclude(attrs):
    try:
        return attrs['include']
    except:
        return ""

def getlogstream(attrs):
    try:
        return attrs['logstream']
    except:
        return ""
def getnamespaces(attrs):
    try:
        return attrs['namespaces']
    except:
        return ''
def member_name(x):
    return "%s_"%x

    
def op_name(x):
    return "OP_%s"%x

def handler_name(name):
    return "handle_%s"%name


def default_attrs(node,name,service,strand):
    dattrs=config.Mapping()
    dattrs['name']=getattr(node,'name',name)
    dattrs['ctor']=getattr(node,'ctor','')
    dattrs['op']=getattr(node,'op','')
    dattrs['handler']=getattr(node,'handler','const bs::error_code& ec')
    dattrs['handler_name']=getattr(node,'handler_name',handler_name(name))
    dattrs['op_type']=getattr(node,'op_type','') #sync/chain or async or fsm
    dattrs['handler_type']=getattr(node,'handler_type','') #'wait_last' or wait_any or wait_all or fsm
    dattrs['skip'] = getattr(node,'skip','false')
    if len(service):
        dattrs['service']=getattr(node,'service',service)
    if len(strand):
        dattrs['strand']=getattr(node,'strand',strand)
    return dattrs

def PreOrderWalkTree(root,extra=False,depth=0):
    yield depth,root
    if confLayerHasItems(root):
        for f in root.iterkeys():
            for x in PreOrderWalkTree(root[f],extra=extra,depth=depth+1):
                yield x

def LayerAttributes(node):
    """Levels out classes names and their attributes;
    for current layer - specified in node -
    returns a list of dictionaries, one for each
    node in current conf mapping, filled with
    default values if none is present"""

    keys=GetLayerClasses(node)
    FullAttrs=[]
    for k in keys:
        attrs=GetAttrs(node[k])
        if not 'name' in attrs.keys():
            xnode=default_attrs(node[k],k,getservice(node[k]),getstrand(node[k]))
            attrs=GetAttrs(xnode)
        FullAttrs.append(attrs)
    return FullAttrs

def PropagateServiceInSubtree(layer,service=None):
    global_serv=service
    if confLayerHasItems(layer):
        FullAttrs=LayerAttributes(layer)
        FullNames=GetLayerClasses(layer)
        if 'service' in layer.keys():
            global_serv=layer['service']
        for i in xrange(len(FullAttrs)):
            Attrs=FullAttrs[i]
            if global_serv:layer[FullNames[i]]['service']=global_serv
            PropagateServiceInSubtree(layer[FullNames[i]],service=global_serv)

def PropagateStrandsInSubtree(layer,strand=None):
    global_strand=strand
    if confLayerHasItems(layer):
        FullNames=GetLayerClasses(layer)
        FullAttrs=LayerAttributes(layer)
        
        sstrand=getstrand(layer)
        if len(sstrand):   global_strand=layer['strand']
        #else:print FullAttrs
        for i in xrange(len(FullNames)):
            if global_strand and len(getstrand(FullAttrs[i]))==0:
                layer[FullNames[i]]['strand']=global_strand
            PropagateStrandsInSubtree(layer[FullNames[i]],strand=global_strand)

def PropagateIncludesInSubtree(layer,include=''):
    global_incl=include
    #print global_incl
    if 'include' in layer.keys():
            global_incl=layer['include']
    elif not 'include' in layer.keys() and len(global_incl):
        layer['include']=global_incl

    if confLayerHasItems(layer):
        FullAttrs=LayerAttributes(layer)
        FullNames=GetLayerClasses(layer)
        for i in xrange(len(FullAttrs)):
            Attrs=FullAttrs[i]
            if len(global_incl):   layer[FullNames[i]]['include']=global_incl
            PropagateIncludesInSubtree(layer[FullNames[i]],include=global_incl)

def PropagateLogStreamInSubtree(layer,log=None):
    #print log
    global_log=log
    if not 'logstream' in layer.keys():
        layer['logstream']=global_log
    if confLayerHasItems(layer):
        FullAttrs=LayerAttributes(layer)
        FullNames=GetLayerClasses(layer)
        if 'logstream' in layer.keys():
            global_log=layer['logstream']
        for i in xrange(len(FullAttrs)):
            Attrs=FullAttrs[i]
            if global_log:layer[FullNames[i]]['logstream']=global_log
            PropagateLogStreamInSubtree(layer[FullNames[i]],log=global_log)


def writeClassToPath(Class,basedir='.',stream=None,gen_inline=False):
    if isSkippable(Class):print "%s isSkippable"%getattr('name',Class,'unknown')
    if gen_inline or len(Class.template_class):inline=True
    else:inline=False
    if stream==None and not isSkippable(Class):
        with open(os.path.join(basedir,Class.headerName()),"wt+") as stream:
            print >>stream,Class.headerBody(inline=inline)
        if Class.sourceBody(inline=inline)!=None:
            with open(os.path.join(basedir,Class.sourceName()),"wt+") as stream:
                print >>stream,Class.sourceBody()
    else:
        print Class.headerBody(inline=inline)
        if Class.sourceBody(inline=inline)!=None:
            print Class.sourceBody()


def printFilesGeneratedOutputTo(Items,basedir='Code',stream=None,cleanup=True,full_inline=False):
    if stream==None:
        if isSkippable(Items): print "Not cleaning up, has skippables"
        if cleanup and not isSkippable(Items):
            try:
                shutil.rmtree(basedir)
            except:pass
        try:
                os.makedirs(basedir)
        except:pass
    for Item in Items:
        #print "isSkippable item:%s %r"%(Item.name,isSkippable(Item))
        if isSkippable(Item):
            print "isSkippable item:%s"%Item.name
        else:
            xpath=os.path.join(*map(lambda x:x.strip(),[basedir]+Item.namespaces))
            #print "path:%s"%xpath
            try:
                os.makedirs(xpath)
            except:pass
            writeClassToPath(Item,basedir=xpath,stream=stream,gen_inline=full_inline)

def setGlobalDefaults(Conf):
    TopName=GetLayerClasses(Conf)[0]
    if 'service' in Conf[TopName].keys():
        topservice=Conf[TopName]['service']
    else:
        topservice='ba::io_service& ios_master'
    PropagateServiceInSubtree(Conf,service=topservice)
    PropagateStrandsInSubtree(Conf)
    PropagateIncludesInSubtree(Conf)
    #PropagateLogStreamInSubtree(Conf,log="std::ostream& log_stream") #use google glog

def remove_ref(x):
    return x.replace('&','')

def get_members(attrs):
    try:
        return attrs['members']
    except: return ''

def contains(arglist,arg):
    flags=map(lambda x:("-".join(x).replace(' ','').replace('&',''))==("-".join(arg).replace(' ','').replace('&','')),arglist)
    return any(flags)

def append_arglist_except(ilist,alist,elist):
    for arg in alist:
        if contains(ilist,arg): continue
        if contains(elist,arg): continue
        ilist.append(arg)
    return ilist
    
def ComputeSubtreeParamsArgs(Conf):
    members          = []
    lmembers         = []
    arglist          = []
    initializer_list = []
    ctor_list        = []
    muniq            = []
    service_list     = []
    strand_list      = []
    logger_list      = []
    mlist            = argList(get_members(Conf))
    for member in mlist:
        lmembers.append([(remove_ref(member[0]),member_name(member[1])),{'access':'private'}])


    for depth,layer in PreOrderWalkTree(Conf,extra=False):
        if confLayerHasItems(layer):
            Attrs=GetAttrs(layer)
            #pprint.pprint(Attrs)
            if len(Attrs)==0 :continue
            #if len(Attrs)==0 or not Attrs.has_key('op'):continue
            #if len(Attrs)==0 or not Attrs.has_key('ctor'):continue
            alist=[]
            attrlist=argList(get_op(Attrs))
            for arg in attrlist:
                argname=arg[1]
                if not argname in map(lambda x:x[1],arglist):
                    alist.append([arg[0],argname])
                member=argname
                membertype=arg[0]
                if not member in muniq:
                    muniq.append(member)
                    members.append([(membertype,member),{'access':'private'}])

            local_members = argList(get_members(Attrs))
            mlist += local_members
            
            blist      = argList(get_ctor(Attrs))
            c_list  =  append_arglist_except(ctor_list,blist,mlist)
            ctor_list=c_list
            
            arg_list     = append_arglist_except(arglist,alist,mlist+ctor_list)
    	    arglist      = arg_list

            s=argList(getservice(Attrs))

            if not argListFlat(s)[0] in argListFlat(service_list):
                service_list += s
            s=argList(getstrand(Attrs))
            if len(s)>0 and not argListFlat(s)[0] in argListFlat(strand_list):
                strand_list  += s
            s=argList(getlogstream(Attrs))
            if len(s)>0 and not argListFlat(s)[0] in argListFlat(logger_list):
                logger_list  += s
            
    return  ctor_list,arglist,initializer_list,lmembers,service_list,strand_list,logger_list

    
def common_includes():
    includes  = []
    includes += ["#include <boost/bind.hpp>"]
    includes += ["#include <boost/shared_ptr.hpp>"]
    includes += ["#include <boost/enable_shared_from_this.hpp>"]
    includes += ["#include <boost/asio.hpp>"]
    includes += [""]
    includes += ['#include "patterns/command.hpp"']
    includes += ['#include "patterns/handlers.hpp"']
    includes += ['']
    includes += ['#include "logging/logging.hpp"']
    includes += ['']
    includes += ["namespace pcmd=patterns::command;"]
    includes += ["namespace phdl=patterns::handlers;"]
    includes += ["namespace ba=boost::asio;"]
    includes += ["namespace bs=boost::system;"]
    includes += ["namespace bt=boost::posix_time;"]
    includes += [""]
    return includes



def createClass(Attrs,ctor_list,initializer_list,services,strands,loggers,includes,namespaces,body=' '):
    name=Attrs['name']
    print "createClass:",name
    

    Class=ClassHolder(name,inherits=['public boost::enable_shared_from_this<%s>'%name,'private boost::noncopyable'],
                      includes=[]+includes,srcincludes=[]+includes,namespaces=namespaces)
    service = argList(getservice(Attrs))
    strand  = argList(getstrand(Attrs))
    logger  = argList(getlogstream(Attrs))
    build_list=services+strands+logger+ctor_list
    init_list=list(set(initializer_list))
    ctor_args    = argListFlat(build_list)
    initializers=["%s(%s)"%(member_name(a[1]),a[1]) for a in build_list]
    Class.add_member('std::string','name_',access='private')
    Class.add_method('',name,margs=ctor_args,initializers=initializers,body=body,access='private')
    Class.add_member('typedef boost::shared_ptr<%s>'%name,'pointer')
    ctor_vals=",".join(actualArgList(map(lambda x:x.split(),ctor_args)))
    Class.add_method('boost::shared_ptr<%s>'%name,'create',margs=ctor_args,modifier='static',
                     body='\nreturn boost::shared_ptr<%s>(new %s(%s));\n'%(name,name,ctor_vals))
    #print ctor_vals
    #Class.add_templated_method(['...Args'],'pointer','create',margs=['Args&& ...args'],modifier='static',
    #                           body=' return boost::shared_ptr<%s>(new %s(std::forward<Args>(args)...));'%(name,name))
    
    for a in build_list:
        Class.add_member(a[0],member_name(a[1]),access='private')
    Class.add_method('','~%s'%name,access='public',modifier='virtual',body='    DLOG(INFO)<<name_<<"::"<<__FUNCTION__<<std::endl;')
    if confIsSkippable(Attrs):Class.skip=True
        
    return Class

def body_lines(code_list,indent=8):
    #acode_list=code_list[1:-1]
    return('\n'+indent*' ').join(code_list)

def append_handler(Class,handler_name,enum_name,enum_names,handler_args,common_args=[]):
    #print '\t',handler_name    
    handler_body=[""]
    handler_body += [""]
    #handler_body += ['//DLOG(INFO)<<name_<<"::"<<__FUNCTION__<<" use_count:"<<shared_from_this()->use_count()-1;']
    handler_body += ['LOG(INFO)<<name_<<"::"<<__FUNCTION__<<"["<<ec<<"]";']
    handler_body += [""]
    handler_body += ["if(!ec)"]
    handler_body += ["{"]
    for i in xrange(len(handler_args)):
        p=printable(remove_ref(handler_args[i][0]).strip())
        if len(p):
            handler_body += ['    %s<<__FUNCTION__<<":%s:\\t"<<%s%s;'%\
                        ("LOG(INFO)",remove_ref(handler_args[i][1]),remove_ref(handler_args[i][1]),p)]
    
    handler_body += [""]
    handler_body += ["}"]
    handler_body += [""]

    for arg in common_args:
        Class.add_member(arg[0],member_name(arg[1]),access='private')
        handler_body+=["    %s = %s"(member_name(arg[1]),arg[1])]
    for name in enum_names:
        if name!=enum_name:
            handler_body += ['//%s && %s->cancel();'%(member_name(name),member_name(name))]
    handler_body +=["\n"+4*' ']
    Class.add_method('void',handler_name,margs=argListFlat(handler_args),body=body_lines(handler_body,indent=12))


#Compute.....
#Class=GenClass(FullAttrs)
#Class.add_handler(layer[key]['handler']),compare with FullAttrs['handler']
#compute exec handler part (compose/branched), wait_any, wait_all
#compute exec cmd part (stack, flat; depending on async-type)
#add storage members, if handler arguments match, if op match
#do exec part

    
def extend_with_templated_exec(Class,arg_list,ebody=[],instances=[]):
    body=[""]
    body += ['try{']
    body += ['    LOG(INFO)<<name_<<"::"<<__FUNCTION__;']
    #body += ['    //DLOG(INFO)<<name_<<"::"<<__FUNCTION__<<" use_count:"<<shared_from_this()->use_count()-1;']

    for i in xrange(len(arg_list)):
        p=printable(remove_ref(arg_list[i][0]).strip())
        if len(p):
            body += ['%s<<"%s:\\t"<<%s%s;'%\
                        ("    DLOG(INFO)",remove_ref(arg_list[i][1]),remove_ref(arg_list[i][1]),p)]
    body += ebody
    body += ['    return true;']
    body += ['}']
    body += ['catch(std::exception &e){']
    body += ['   LOG(WARNING)<<name_<<"::"<<__FUNCTION__<<":"<<e.what();']
    body += ['   cancel();']
    body += ['   return false;']
    body += ['}']
                        
    body +=["\n"+4*' ']
    Class.add_templated_method(['Handler'],'bool','exec',margs=argListFlat(arg_list)+
                        ['Handler& handler'],body=body_lines(body,indent=8),instances=instances)

def extend_with_adapter(Class,who,arg_list,top_arg_list):
        adapt_body="handler(%s);"%(",".join(actualArgList(top_arg_list)))
        Class.add_templated_method(['Handler'],'void','adapter_%s'%who,margs=['Handler& handler']+argListFlat(arg_list),body=adapt_body)
    
def extend_with_exec(Class,arg_list,ebody=[]):
    body=[""]
    body += ['try{']
    body += ['    LOG(INFO)<<name_<<"::"<<__FUNCTION__;']
    #body += ['    //DLOG(INFO)<<name_<<"::"<<__FUNCTION__<<" use_count:"<<shared_from_this()->use_count()-1;']

    for i in xrange(len(arg_list)):
        p=printable(remove_ref(arg_list[i][0]).strip())
        if len(p):
            body += ['    %s<<"%s:\\t"<<%s%s;'%\
                        ("LOG(INFO)",remove_ref(arg_list[i][1]),remove_ref(arg_list[i][1]),p)]
    body += ['    std::vector<pcmd::action_t> components_;']                        
    body += ebody
    
    body += ['    return true;']
    body += ['}']
    body += ['catch(std::exception &e){']
    body += ['   LOG(WARNING)<<name_<<"::"<<__FUNCTION__<<":"<<e.what();']
    body += ['   return false;']
    body += ['}']
                        
    body +=["\n"+4*' ']
    Class.add_method('bool','exec',margs=argListFlat(arg_list),body=body_lines(body,indent=8))

def extend_with_cancel(Class,names):
    body=[""]
    body += ['try{']
    body += ['    bool retcode=true;']
    body += ['    LOG(WARNING)<<name_<<"::"<<__FUNCTION__;']
    for name in names:
        body += ['    retcode &= (%s && %s->cancel());'%(member_name(name),member_name(name))]
    body += ['    return retcode;']
    body += ['}']
    body += ['catch(std::exception &e){']
    body += ['   LOG(WARNING)<<name_<<"::"<<__FUNCTION__<<":"<<e.what();']
    body += ['   return false;']
    body += ['}']
    body +=["\n"+4*' ']
    Class.add_method('bool','cancel',margs=[],body=body_lines(body,indent=8))

    
def namespacesList(x):
    return getnamespaces(x).split(',')
def namespacesCompose(x):
    return "::".join(getnamespaces(x).split(','))
def includeList(x):
    return getinclude(x).split(',')
def namespacePath(x):
    xns=namespacesList(x)
    if len("".join(xns)): xpath=os.path.join(*xns)+'/'
    else:                 xpath=''
    return xpath

def compName(x):
    return "%s_op"%x.strip()

def addCompsEnum(Class,names):
    Class.add_member('enum','cnames{%s}'%", ".join(map(compName,names)),access='public')

def addCompsContainer(Class):
    #Class.add_member('std::vector<pcmd::action_pair_t>','components_',access='private')
    Class.add_member('std::string','name_',access='private')
    
def buildCtorBody(ncomponents,init_links=False):
    code  = [""]
    code += ["name_=std::string(__FUNCTION__);"]
    code += ['DLOG(INFO)<<name_<<"()";']
    if init_links: code += ['init_components();']
    #if ncomponents>0:
    #    code += ['components_.resize(%d);'%ncomponents]
    code += ['\n    ']
    return body_lines(code,indent=8)

def bound_name(x):
    return "bound_%s"%(x.strip())
def functor_name(x):
    return "op_%s"%(x.strip())

def refArgListMembers(actualArgs,members):
    actual_args=[]
    member_names = map(lambda x:x[0][1],members)
    arg_names    = map(member_name,actualArgs)
    for arg,aarg in zip(arg_names,actualArgs):
        if arg in member_names:
            actual_args+=["boost::ref(%s)"%arg]
        else:
            actual_args+=[aarg]
    return actual_args

def LoopTree(Conf):
    Classes=[]
    for depth,layer in PreOrderWalkTree(Conf,extra=False):
        if confLayerHasItems(layer):
            FullAttrs=LayerAttributes(layer)
            FullNames=GetLayerClasses(layer)
            #pprint.pprint(FullAttrs)

            for name,fAttr in zip(FullNames,FullAttrs):
                build_list,arg_list,initializer_list,members,services,strands,loggers=\
                ComputeSubtreeParamsArgs(layer[name])
                #static depth here? initializer list and member
                xincludes=includeList(layer[name])
                #print xnamespaces
                xnamespaces=namespacesList(layer[name])
                CompNames=GetLayerClasses(layer[name])
                ncomponents=len(CompNames)

                CompAttrs=LayerAttributes(layer[name])
 
                Class=createClass(fAttr,build_list,initializer_list,services,
                                  strands,loggers,common_includes()+xincludes,
                                  xnamespaces,body=buildCtorBody(ncomponents,init_links=False))#(len(CompAttrs)>0)))

                
                for m in members:Class.add_member(*m[0],**m[1])
                init_body =['']
                memberlist=[]
                ebody=[]
                wbody=[]
                adapted=False
                for attr in CompAttrs:
                    print '\t',name,attr['name']
                    xpath = namespacePath(layer[name][attr['name']])
                    Class.add_include(['#include "%s%s.hpp"'%(xpath,attr['name'])])
                    #Class.add_include(['class %s%s;'%(namespacesCompose(layer[name][attr['name']]),attr['name'])])
                    #print Class.includes
                    append_handler(Class,
                            handler_name(attr['name']),
                            attr['name'],
                            CompNames,
                            argList(attr['handler']),
                            common_args=[]
                        )
                    child_params,child_arg_list,_,_,serv,strs,logs=ComputeSubtreeParamsArgs(layer[name][attr['name']])

                    placeholders=['shared_from_this()']+['_%d'%(k+1) for k in range(len(argList(attr['handler']))) ]                    
                    inline_placeholders=",".join(placeholders)

                    bindargs=formalArgList(argList(attr['handler']))
                    inline_bindargs=",".join(bindargs)
                    
                    #bound_type='boost::function<void(%s)>'%inline_bindargs
                    bound_type='auto'
                    ptrname='%s'%("::".join(namespacesList(layer[name][attr['name']])+[attr['name']])).lstrip(':')
                    args_=map(member_name,actualArgList(serv+strs+logs+child_params))
                    mkptr="%s::create(%s)"%(ptrname,",".join(args_))
                    
                    bound_handler_name = bound_name(handler_name(attr['name']))
                    comp_name          = functor_name(attr['name'])
                    #print members,actualArgListFlat(child_arg_list)
                    actual_args=refArgListMembers(actualArgList(child_arg_list),members)
                    #print actual_args
                    wrap_args          = ",".join([member_name(attr['name'])]+actual_args+[bound_handler_name]).replace(',,',',')
                    #wrap_args          = ",".join([member_name(attr['name'])]+[actualArgListFlat(child_arg_list)]+[bound_handler_name]).replace(',,',',')
                    #wrap args needs to compare with members and boost::ref it on local members. they are used to pass params between children
                    #print wrap_args #,[member_name(attr['name'])]+[actualArgListFlat(arg_list)]+[bound_handler_name]
                    ebody += ['    %s'%bound_type]
                    ebody += ['        %s = boost::bind(&%s::%s,%s);'%(bound_handler_name,name,handler_name(attr['name']),inline_placeholders)]

                    if not sameSignature(argList(attr['handler']),argList(fAttr['handler'])):
                        free_placeholder_list=['shared_from_this()','boost::protect(handler)']+['_%d'%(k+1) for k in range(len(argList(attr['handler']))) ]
                        free_placeholders=", ".join(free_placeholder_list)
                        extend_with_adapter(Class,handler_name(attr['name']),argList(attr['handler']),argList(fAttr['handler']))
                        ebody += ["    auto adapted_%s ="% handler_name(attr['name'])]
                        ebody += ["         boost::bind(&%s::adapter_%s<protected_handler_t>,%s);"%(name,handler_name(attr['name']),free_placeholders)]
                        adapted=True
                    wbody  = ['    pcmd::action_t %s = pcmd::wrap(%s);'%(comp_name,wrap_args)]+wbody
                    
                    memberlist.append([('boost::shared_ptr<%s>'%ptrname,member_name(attr['name'])),{'access':'private'}])
                    init_body +=['   if(!%s) %s = %s;'%(member_name(attr['name']),member_name(attr['name']),mkptr)]

                if adapted:
                    Class.add_include(['#include <boost/bind/protect.hpp>'])
                if adapted:
                    ebody = ['    typedef decltype(boost::protect(handler)) protected_handler_t;']+ebody
                if len(memberlist)>0:
                    Class.add_method('void','init_components',margs=[],body=body_lines(init_body,indent=8) )
                    for mm in memberlist[::-1]:  Class.add_member(*mm[0],**mm[1])
                    ebody  = ['    init_components();']+ebody
                    ebody += wbody
                """not sure, this looks unneeded"""
                """if len(CompNames)==0:
                    print '\t',name,'default_handler'
                    append_handler(Class,
                            handler_name(fAttr['name']),
                            None,[],
                            argList(attr['handler']),
                            common_args=[]
                        )"""
                xpath = namespacePath(layer[name])
                Class.add_srcinclude(['#include "%s%s.hpp"'%(xpath,name)])
                if len(fAttr['handler']):
                    extend_with_templated_exec(Class,arg_list,ebody=ebody,instances=[])
                else:
                    print "no template:",name,fAttr['handler']
                    extend_with_exec(Class,arg_list)
                extend_with_cancel(Class,CompNames)
                if ncomponents>0:
                    addCompsContainer(Class)
                    #addCompsEnum(Class,CompNames)
                #print '*'
                Classes.append(Class)
    return Classes

            
            
if __name__=='__main__':
    sys.argv.append('design/TcpConnect.config')
    if len(sys.argv)>1:
        Cfile=sys.argv[1]
    else:
        print "Needs a config {} as argument"
        sys.exit(1)
    print "Generating for:%s"%Cfile
    Conf=LoadConfig(Cfile)
    setGlobalDefaults(Conf)
    Actions=LoopTree(Conf)
    package=Conf.keys()[0]
    printFilesGeneratedOutputTo(Actions,basedir='Code/%s'%package,cleanup=True,full_inline=False)
